# coding=utf-8
import json, re
import allure
from jsonpath import jsonpath
from api.common_api import Common_Api
from common.logger import Logger


def jp(obj, expr, result_type='VALUE', debug=0, use_eval=True):
    Logger.info(f'jsonpath表达式：{expr}')
    return jsonpath(obj, expr, result_type='VALUE', debug=0, use_eval=True)

class Approve_Process(Common_Api):

    def get_process_node(self, process_name=None, body=None,functionpage='Handle',action='todo'):
        """
        传入流程名称或者整个body来查询当前用户的待办或者已办列表信息。Handle(我办理的流程)下有todo、done、circulate、cc。Initiate(我发起的流程)下有doing、archived、draft
        :param process_name: 流程名称
        :param body: 请求body，如：{"page":1,"pagesize":10,"where":[],"functionpage":"Handle","action":"todo","type":"","order_by":{}}
        :return:
        """
        if not process_name:
            json_body = body
        else:
            print(f"流程名称：{process_name}")
            json_body = {"page": 1, "pagesize": 20, "where": [
                {"type": "classifytree", "name": "流程分类", "showname": "流程分类", "field": "classify", "placeholder": "",
                 "group": "aa", "col_md": 1, "value": ""},
                {"type": "org", "name": "发起组织", "showname": "发起组织", "field": "BuGuid", "placeholder": "请选择",
                 "group": "bb",
                 "col_md": 1, "value": ""},
                {"type": "likemore", "name": "", "field": "initiater_name,instance_name", "showname": "流程名称、发起人",
                 "placeholder": "请输入流程名称、发起人", "group": "bb", "col_md": 3, "btnSearch": True,
                 "value": process_name},
                {"type": "like", "name": "发起人", "showname": "发起人", "field": "initiater_name", "placeholder": "请输入发起人",
                 "group": "bb", "col_md": 1, "value": ""},
                {"type": "data_range", "name": "", "showname": "发起时间", "field": "initiate_time",
                 "placeholder": {"begin": "发起开始时间", "end": "发起结束时间"}, "group": "bb", "col_md": 6, "value": ""}],
                         "functionpage": functionpage, "action": action, "type": "", "order_by": {}}
        token = self.get_token('/flowcenter/flow/new')
        url = '/flowcenter/list/ajax-search-nodes'
        resp = self.send(url, payload=json_body, method='post', X_CSRF_Token=token)
        return resp

    @allure.step('打开审批流程')
    def open_process_instance(self, process_name='', node_id='',proc_id='',package_id='',url=''):
        """
        通过流程名称打开流程实例，或者通过node_id，proc_id，package_id打开流程实例，或者直接传入url打开流程。
        :param node_id: 节点id
        :param proc_id: 流程id
        :param package_id: 模板id
        :param url: 打开流程ur
        :return:
        """
        if node_id and proc_id and package_id:
            approve_url = f'/flowinstance/approval/index?node_id={node_id}&proc_id={proc_id}&package_id={package_id}&oid='
        elif url:
            approve_url = url
        else:
            # 通过流程名称获取待办url
            resp = self.get_process_node(process_name)
            resp_json = json.loads(resp.text)
            if jsonpath(resp_json, f'$.data.list[?(@.proc_name=="{process_name}")]'):
                # approve_url = self.jsonpath_value(json.loads(resp.text), f'$.data.list[?(@.proc_name=="{process_name}")].approval_url')
                node_id = self.jsonpath_value(resp_json, f'$.data.list[?(@.proc_name=="{process_name}")].node_id')
                proc_id = self.jsonpath_value(resp_json, f'$.data.list[?(@.proc_name=="{process_name}")].proc_id')
                package_id = self.jsonpath_value(resp_json, f'$.data.list[?(@.proc_name=="{process_name}")].package_id')
                approve_url = f'/flowinstance/approval/index?node_id={node_id}&proc_id={proc_id}&package_id={package_id}&oid='
            else:
                assert False, f'当前用户无【{process_name}】流程待办节点！'
        print(f"approval_url={approve_url}")
        self.send(url=approve_url, method='get')    # 没啥用的请求了
        # 接口请求得到params和tplData
        url_params = approve_url.split('?')[1]  # 获取到get的参数字符串
        if url != '':
            full_get_process_info_url = url.replace('approval/index', 'approval/get-process-info')
            resp = self.get_process_info_by_approve(full_url=full_get_process_info_url)
        else:
            resp = self.get_process_info_by_approve(url_params)
        return resp

    @allure.step('切换审批按钮')
    def get_approve_option(self, action):
        """
        切换审批按钮
        :param action: 审批动作：表决|同意|驳回|协商|交办|终止|作废|加签|归档
        :return:
        """
        if action == '表决':
            action = 'Vote'
        elif action == '同意':
            action = 'Pass'
        elif action == '驳回':
            action = 'RollBack'
        elif action == '协商':
            action = 'Consult'
        elif action == '回复协商':
            action = 'ReplyConsult'
        elif action == '交办':
            action = 'Assigned'
        elif action == '终止':
            action = 'Terminate'
        elif action == '作废':
            action = 'Cancel'
        elif action == '加签':
            action = 'AddSign'
        elif action == '归档':
            action = 'Book'
        elif action == '发起':
            action = 'Initiate'
        else:
            action = 'Pass'
        # 根据打开流程实例的响应内容，组装get_approve_option请求参数
        package_id = self.jsonpath_value(self.tpldata_json, '$.package_id')
        # 子流程发起时，proc_id的jsonpath路径：$.form.form_data.wfObjectInfo.id
        proc_id_list = jsonpath(self.tpldata_json,'$.form.form_data.wfObjectInfo.proc_id')
        if not proc_id_list:    # 如果正常流程查不到ID，用例子流程路径查id
            proc_id_list = jsonpath(self.tpldata_json, '$.form.form_data.wfObjectInfo.id')
        proc_id = proc_id_list[0]
        node_id = self.jsonpath_value(self.tpldata_json, '$.NodeInfo.node_id')
        step_type = self.jsonpath_value(self.tpldata_json, '$.StepInfo.step_type')
        # 发送请求
        url = '/flowinstance/approval/get-approve-options'
        json_body = {"action": action, "package_id": package_id,
                     "proc_id": proc_id,
                     "node_id": node_id, "step_type": step_type, "opinion": None,
                     "is_sub_process_start": None}
        # 协商和发起协商没有is_end_task入参
        if action not in ['Consult','ReplyConsult']:
            is_end_task = self.jsonpath_value(self.tpldata_json, '$.NodeInfo.is_end_task')
            json_body.update({"is_end_task": is_end_task})
        resp = self.send(url, method='post', payload=json_body)
        return resp

    def get_default_option(self, approve_params):
        """
        获取默认审批意见
        :param approve_params:
        :return:
        """
        resp = self.get_approve_option(approve_params['action'][0])
        resp_json = json.loads(resp.text)
        opinion = self.jsonpath_value(resp_json, '$.data.DefaultOption')
        return opinion

    def _approve_base_body_build(self, approve_params, open_instance_response=None, user_orgs_resp=None):
        """
        通过打开流程详情返回的Params和tpldata，构建基础审批请求体json
        :param approve_params: yml中的输入参数；
        :param open_instance_response: 打开流程详情的请求响应；
        :param user_orgs_resp:  获取用户组织信息的请求响应；
        :return: 请求体json：approve_base_body。
        """
        if open_instance_response is None:
            process_name = self.parse_params(approve_params,'process_name')
            open_instance_response = self.open_process_instance(process_name)
        open_instance_resp = self.get_key_by_process_instance(open_instance_response)
        token = open_instance_resp['token']
        # 获取审批人的默认组织信息
        if user_orgs_resp is None:
            user_orgs_resp = self.get_user_orgs(token=token)
        # 如果默认组织能返回数据，则取默认组织，否则取第一个组织
        default = jp(user_orgs_resp.json(),'$.data.departData[?(@.is_default==1)].name_path')
        if default:
            name_path = self.jsonpath_value(json.loads(user_orgs_resp.text),
                                            '$.data.departData[?(@.is_default==1)].name_path')
            org_id = self.jsonpath_value(json.loads(user_orgs_resp.text), '$.data.departData[?(@.is_default==1)].org_id')
        else:
            name_path = jp(user_orgs_resp.json(),f'$.data.departData[?(@.is_default==0)].name_path')[0]
            org_id = jp(user_orgs_resp.json(),'$.data.departData[?(@.is_default==0)].org_id')[0]

        # *********************从tpldata中获取提交请求的部分入参*********************
        # 默认抄送从后台抄送了，不需要拿参数了
        # default_cc = jsonpath(self.params_json, '$.cc[*].auditor_guid')   # 默认抄送人的用户guid：["A3FF8274-7B22-4AEB-7474-08D9AEDE6EC9","1A4A98D0-20B7-4915-9562-08D97C49D286"]
        # if default_cc:
        #     step_cc_list = self.jsonpath_value(user_orgs_resp.json(),'$.data.step_cc_list')
        # else:   # jsonpath获取不到默认抄送，则为空列表
        step_cc_list = []
        opinion = self.get_default_option(approve_params)
        actuals = []
        branch_choose = []
        archived_directory_id = self.jsonpath_value(self.tpldata_json, '$.StepInfo.archived_directory_id')
        manual_execution = False
        _prc_name_ = self.jsonpath_value(self.tpldata_json, '$.ProcessInfo.Title')
        form_data = {}
        children = self.jsonpath_value(self.tpldata_json, '$.form.form_data.children')
        fieldSources = self.jsonpath_value(self.tpldata_json, '$.form.form_data.fieldSources')
        main = self.jsonpath_value(self.tpldata_json, '$.form.form_data.main')
        OprVersion = self.jsonpath_value(self.tpldata_json,'$..OprVersion')
        # 更新表单值
        # form_values = [['申请类型', '1'], ['总裁办是否已批营销计划', '1']]
        form_values = self.parse_params(approve_params, 'form_values', 1)
        if form_values:
            for form in form_values:
                field_code = jsonpath(self.tpldata_json,
                                      f'$.form.data_define.main.fields[?(@.name=="{form[0]}")].code')
                print(f'field_code={field_code}')
                main[field_code[0]] = form[1]
        attachmentTypes = self.jsonpath_value(self.tpldata_json, '$.form.form_data.attachmentTypes')
        form_data.update(children=children, fieldSources=fieldSources, main=main, attachmentTypes=attachmentTypes)

        # ********************组装approve_process入参*******************
        approve_base_body = {}
        print(self.params_json)
        approve_base_body.update(self.params_json)
        approve_base_body.update(form_data=form_data, step_cc_list=step_cc_list, opinion=opinion, actuals=actuals,
                                    branch_choose=branch_choose,
                                    archived_directory_id=archived_directory_id, manual_execution=manual_execution,
                                    _prc_name_=_prc_name_)
        approve_base_body.pop('data_control')
        approve_base_body['initiater']['initiater_org_id'] = org_id
        approve_base_body['initiater']['initiater_org_name'] = name_path
        # 20230316新增流程调整版本参数OprVersion
        approve_base_body['OprVersion'] = OprVersion
        if self.jsonpath_value(approve_base_body, '$.sign_id') == None:
            approve_base_body['sign_id'] = ''
        return approve_base_body

    @allure.step('审批前校验')
    def valid_pass(self, approve_params, open_instance_response=None, user_orgs_resp=None):
        """
        审批前校验，仅审批，表决，归档接口使用此校验
        :param approve_params:
        :param open_instance_response:
        :param user_orgs_resp:
        :return:
        """
        process_name = self.parse_params(approve_params, 'process_name')
        action = self.parse_params(approve_params, 'action')
        # 请求体
        approve_base_body = self._approve_base_body_build(approve_params, open_instance_response, user_orgs_resp)
        url = f'/flowinstance/approval/valid-pass?prc_name={process_name}'
        body = self._import_approve_body()
        if action[0] == '表决':
            approve_process_body = body.vote_param(approve_params, approve_base_body,
                                                   user_orgs_resp=self.user_orgs_resp, tplData=self.tpldata_json)
        else:
            approve_process_body = body.pass_param(approve_params, approve_base_body,
                                               user_orgs_resp=self.user_orgs_resp, tplData=self.tpldata_json)
        resp = self.send(url, method='post', payload=approve_process_body,enable_vtk=1)
        # if resp.status_code != 200 and resp.json()['code'] != 1:
        #     assert False, f'接口{url}校验失败：返回\n{resp.json()}'
        return resp

    @allure.step('审批')
    def approve(self,approve_params, approve_base_body):
        body = self._import_approve_body()
        process_name = self.parse_params(approve_params, 'process_name')
        approve_process_body = body.pass_param(approve_params, approve_base_body,
                                               user_orgs_resp=self.user_orgs_resp,tplData=self.tpldata_json)
        url = f'/flowinstance/approval/pass?prc_name={process_name}'
        resp = self.send(url, method='post', payload=approve_process_body)
        return resp

    @allure.step('子流程发起')
    def subprocess_initiate(self,approve_params,open_process_resp):
        """
        子流程发起
        :param approve_params: 子流程发起参数
        :param open_process_resp: 打开流程的响应
        :return:
        """
        from api.FlowInstance.create_process import Create_Process
        # 发起意见，如果传入action，则获取默认意见
        action = self.parse_params(approve_params,'action',1)
        if action==None:
            opinion = self.get_default_option(approve_params)
        else:
            opinion = action[1]['handText']
        # 由于需要将Approve_Process里面的self.csrf_token传给Create_Process，使用setattr方式给Create_Process设置类变量
        setattr(Create_Process,'csrf_token',self.csrf_token)
        # 发起子流程
        resp = Create_Process(self.session).initiate_submit(approve_params,open_process_resp=open_process_resp,opinion=opinion)
        return resp

    @allure.step('表决')
    def vote(self,approve_params, approve_base_body):
        body = self._import_approve_body()
        process_name = self.parse_params(approve_params, 'process_name')
        approve_process_body = body.vote_param(approve_params, approve_base_body,
                                               user_orgs_resp=self.user_orgs_resp)
        url = f'/flowinstance/approval/pass?prc_name={process_name}'
        resp = self.send(url, method='post', payload=approve_process_body)
        return resp

    @allure.step('归档')
    def book(self,approve_params, approve_base_body):
        body = self._import_approve_body()
        process_name = self.parse_params(approve_params, 'process_name')
        approve_process_body = body.pass_param(approve_params, approve_base_body,
                                               user_orgs_resp=self.user_orgs_resp, tplData=self.tpldata_json)
        url = f'/flowinstance/approval/pass?prc_name={process_name}'
        resp = self.send(url, method='post', payload=approve_process_body)
        return resp

    @allure.step('终止')
    def terminate(self,approve_params, approve_base_body):
        body = self._import_approve_body()
        process_name = self.parse_params(approve_params, 'process_name')
        approve_process_body = body.cancel_param(approve_params, approve_base_body,
                                                 user_orgs_resp=self.user_orgs_resp)
        print(f"abort_process_body={approve_process_body}")
        url = f'/flowinstance/approval/termination?prc_name={process_name}'
        resp = self.send(url, method='post', payload=approve_process_body)
        return resp

    @allure.step('作废')
    def cancel(self,approve_params, approve_base_body):
        body = self._import_approve_body()
        process_name = self.parse_params(approve_params, 'process_name')
        approve_process_body = body.cancel_param(approve_params, approve_base_body,
                                                 user_orgs_resp=self.user_orgs_resp)
        print(f"cancel_process_body={approve_process_body}")
        url = f'/flowinstance/approval/invalid?prc_name={process_name}'
        resp = self.send(url, method='post', payload=approve_process_body)
        return resp

    @allure.step('驳回')
    def reject(self,approve_params, approve_base_body):
        body = self._import_approve_body()
        process_name = self.parse_params(approve_params,'process_name')
        approve_process_body = body.rollback_param(approve_params, approve_base_body,
                                                   user_orgs_resp=self.user_orgs_resp,csrf_token = self.csrf_token)
        print(f"rollback_process_body={approve_process_body}")
        url = f'/flowinstance/approval/reject?prc_name={process_name}'
        resp = self.send(url, method='post', payload=approve_process_body)
        return resp

    @allure.step('加签')
    def addSign(self,approve_params, approve_base_body):
        body = self._import_approve_body()
        process_name = self.parse_params(approve_params, 'process_name')
        approve_process_body = body.add_sign_param(approve_params, approve_base_body,
                                                   user_orgs_resp=self.user_orgs_resp)
        print(f"add_sign_process_body={approve_process_body}")
        url = f'/flowinstance/approval/add-sign?prc_name={process_name}'
        resp = self.send(url, method='post', payload=approve_process_body)
        return resp

    @allure.step('交办')
    def assigned(self,approve_params, approve_base_body):
        body = self._import_approve_body()
        process_name = self.parse_params(approve_params, 'process_name')
        approve_process_body = body.assigned_param(approve_params, approve_base_body,
                                                   user_orgs_resp=self.user_orgs_resp)
        print(f"assigned_process_body={approve_process_body}")
        url = f'/flowinstance/approval/assigned?prc_name={process_name}'
        resp = self.send(url, method='post', payload=approve_process_body)
        return resp

    @allure.step('协商')
    def consult(self,approve_params, approve_base_body):
        body = self._import_approve_body()
        process_name = self.parse_params(approve_params, 'process_name')
        approve_process_body = body.consult_param(approve_params, approve_base_body,
                                                  user_orgs_resp=self.user_orgs_resp)
        print(f"consult_process_body={approve_process_body}")
        url = f'/flowinstance/approval/do-consult?prc_name={process_name}'
        resp = self.send(url, method='post', payload=approve_process_body)
        return resp

    @allure.step('回复协商')
    def reply_consult(self,approve_params, approve_base_body):
        body = self._import_approve_body()
        process_name = self.parse_params(approve_params, 'process_name')
        approve_process_body = body.consult_param(approve_params, approve_base_body,
                                                  user_orgs_resp=self.user_orgs_resp)
        print(f"reply_consult_process_body={approve_process_body}")
        url = f'/flowinstance/approval/reply-consult?prc_name={process_name}'
        resp = self.send(url, method='post', payload=approve_process_body)
        return resp

    @allure.step('打开流程后传阅')
    def circulate_by_open_details(self,approve_params):
        process_name = self.parse_params(approve_params, 'process_name')
        process_url = self.parse_params(approve_params, 'process_url')
        subject = self.jsonpath_value(approve_params, '$.action[1].Subject')
        CirculateTo = self.jsonpath_value(approve_params, '$.action[1].CirculateTo')
        # 根据url打开流程
        instance_resp = self.open_process_instance(url = process_url)
        # 根据打开的流程响应，获取传阅接口所需参数
        proc_id = self.get_key_by_process_instance(instance_resp, 'params', '$.proc_id')['value']
        auditor_id = self.jsonpath_value(self.params_json, '$.auditor_id')
        auditor_name = self.jsonpath_value(self.params_json, '$.auditor_name')
        step_id = self.jsonpath_value(self.tpldata_json, '$.StepInfo.step_id')
        node_id = self.jsonpath_value(self.tpldata_json, '$.NodeInfo.node_id')
        # # 判断释放有传阅按钮："MoreButtonList":[{"ButtonName":"传阅","EvalJs":null,"IsHighlight":0,"ModifyDomains":null,"ButtonIcon":"icon-chuanyue","OpenUrl":null,"OperationCode":"Circulate","WithdrawReason":null}]
        # is_can_circulate = self.jsonpath_value(self.tpldata_json, '$.BusinessButtons.MoreButtonList')
        # if not is_can_circulate:    #如果为空列表，表示没有更多按钮，传阅按钮在更多按钮里面
        #     assert False, '没有传阅权限'

        # 获取传阅用户信息
        Circulate_users_list = []
        for user in CirculateTo:
            Circulate_user_info = {}
            user_resp = self.get_users_by_name(user)
            cc_auditor_name = jsonpath(user_resp.json(),'$.data.data[0].name')[0]
            cc_auditor_id = jsonpath(user_resp.json(),'$.data.data[0].id')[0]
            cc_auditor_code = jsonpath(user_resp.json(),'$.data.data[0].code')[0]
            station_name = jsonpath(user_resp.json(),'$.data.data[0].org_settings[?(@.is_default==1)].org_id')[0]
            station_guid = jsonpath(user_resp.json(), '$.data.data[0].org_settings[?(@.is_default==1)].name_path')[0]
            Circulate_user_info['auditor_name'] = cc_auditor_name
            Circulate_user_info['auditor_id'] = cc_auditor_id
            Circulate_user_info['auditor_code'] = cc_auditor_code
            Circulate_user_info['station_name'] = station_name
            Circulate_user_info['station_guid'] = station_guid
            Circulate_users_list.append(Circulate_user_info)

        # 传阅校验json
        validate_json = {"opinion": "验证", "proc_id": proc_id,
                    "step_id": step_id,
                    "node_id": node_id,
                    "cc_list": [], "only_do_validate": True,
                    "initiater": {"initiater_id": auditor_id, "initiater_name": auditor_name}}

        # 正式传阅json
        json_data = {"opinion": subject,
                     "proc_id": proc_id,
                     "step_id": step_id,
                     "node_id": node_id, "cc_list": Circulate_users_list,
                     "initiater": {"initiater_id": auditor_id, "initiater_name": auditor_name}}
        # 根据yml中的参数，决定进行传阅校验还是正式传阅
        Validate_flag = jsonpath(approve_params, '$.action[1].Validate')
        if Validate_flag and Validate_flag[0] == '是':
            body_json = validate_json
        else:
            body_json = json_data

        url = f'/flowinstance/approval/circulate?prc_name={process_name}'
        resp = self.send(url, method='post', payload=body_json, X_CSRF_Token=self.csrf_token)
        return resp

    @allure.step('打开已办流程后催办')
    def reminder_by_open_details(self, approve_params):
        """
        通过打开流程详情进行催办
        :param approve_params:
        :return:
        """
        process_name = self.parse_params(approve_params, 'process_name')
        subject = self.jsonpath_value(approve_params,'$.action[1].Subject')
        # 查询出已办流程的url
        resp = self.get_process_node(process_name,action='done')
        approval_url = self.jsonpath_value(resp.json(),f'$.data.list[?(@.proc_name=="{process_name}")].approval_url')
        # 打开审批已办流程,获取催办的入参数据
        instance_resp = self.open_process_instance(url = approval_url)
        proc_id = self.get_key_by_process_instance(instance_resp,'params','$.flow_id')['value']
        auditor_id = self.jsonpath_value(self.params_json,'$.auditor_id')
        auditor_name = self.jsonpath_value(self.params_json,'$.auditor_name')
        node_ids = jsonpath(self.tpldata_json,'$.urge_nodes[*].node_id')
        body = {"proc_id": proc_id, "subject": subject,
                "node_ids": node_ids,
                "auditors": {auditor_id: auditor_name}}
        url = f'/flowinstance/approval/ajax-do-reminder?prc_name={process_name}'
        resp = self.send(url, method='post', payload=body)
        return resp

    def _import_approve_body(self):
        """
        内部导入Request_Body
        :return:
        """
        # 防止循环导入导致报错，需要在内部导入Request_Body
        from api.FlowInstance.request_body import Request_Body
        body = Request_Body(self.session)
        return body

    @allure.step('审批确认路径')
    def approve_confirm_path(self,approve_params, open_instance_response=None, user_orgs_resp=None,confirm_path = True):
        return self.approve_submit(approve_params, open_instance_response, user_orgs_resp,confirm_path)

    @allure.step('选择分支路径')
    def choose_branch_return(self,approve_params, open_instance_response=None, user_orgs_resp=None,confirm_path = None,choose_branch_return=True):
        return self.approve_submit(approve_params, open_instance_response, user_orgs_resp,confirm_path,choose_branch_return)

    @allure.step('提交审批')
    def approve_submit(self, approve_params, open_instance_response=None, user_orgs_resp=None,confirm_path = None,choose_branch_return=None):
        """
        提交审批
        :param approve_params:  yml中的审批同意参数
        :param open_instance_response:  打开流程的响应
        :param user_orgs_resp:  加载流程中用户信息的响应
        :param confirm_path:  返回打开确认路径页面的响应
        :return:
        """
        process_name = self.parse_params(approve_params, 'process_name')
        # 请求体
        approve_base_body = None
        # 催办、传阅不需要组装审批请求体
        if approve_params['action'][0].lower() not in ['催办','传阅']:
            approve_base_body = self._approve_base_body_build(approve_params, open_instance_response, user_orgs_resp)
        # 如果是打回，则使用打回请求
        if approve_params['action'][0].lower() == '驳回':
            resp = self.reject(approve_params, approve_base_body)
        # 表决请求
        elif approve_params['action'][0].lower() in ['表决', '同意', '归档']:
            # 解析表决参数
            if approve_params['action'][0] == '表决':
                # 审批前校验接口
                valid_pass_resp = self.valid_pass(approve_params, open_instance_response, user_orgs_resp)
                resp = self.vote(approve_params,approve_base_body)
            else:
                # 审批前校验接口
                valid_pass_resp = self.valid_pass(approve_params, open_instance_response, user_orgs_resp)
                resp = self.approve(approve_params,approve_base_body)
            valid_pass_code = jsonpath(valid_pass_resp.json(), '$.code')
            code = jsonpath(resp.json(), '$.code')
            # 由于校验接口不影响实际审批，所以在此进行下校验
            assert code == valid_pass_code, f'校验接口code：{code}与审批接口返回code：{valid_pass_code}不一致'
            print(f"approve_base_body={approve_base_body}")
            # 校验通过，进行再次审批
            url = f'/flowinstance/approval/pass?prc_name={process_name}'
            # 选择步骤责任人,无需选择责任时，允许不传入step_auditor
            choose_step_auditor = self.parse_params(approve_params,'step_auditor',1)
            # 发起不明确路径时，需要选择路径或责任人。code=2，说明需要确认路径或责任人。
            errorCode = jsonpath(resp.json(), '$.data.validateResult.errorCode')
            if code:
                if confirm_path != None:
                    return resp # 返回确认路径的响应
                if code[0] == 2 and errorCode==False:
                    resp = self._confirm_step_path_and_submit(url, approve_base_body, resp, choose_step_auditor)
                # "validateResult":{"errorCode":"30014","message":"分支步骤不明确，请选择分支！"}
                elif code[0] == 2 and errorCode[0]=='30014':
                    # yml文件中解析分支名称
                    branch_name = self.parse_params(approve_params,'branch_names',1)[0]
                    # 选择分支
                    resp = self.choose_branch_step(resp, approve_base_body, branch_name=branch_name)
                    if choose_branch_return != None:    # 返回选择路径后的响应
                        return resp
                    # 确认路径后提交
                    resp = self._confirm_step_path_and_submit(url, approve_base_body, resp, choose_step_auditor)
                # 不明确路径或者路径出现刷新时，给出的校验： "validateResult":{"errorCode":"30003","message":"审批路径发生变化"}
                elif code[0] == 2 and errorCode[0] == '30003':
                    # 确认路径后提交
                    resp = self._confirm_step_path_and_submit(url, approve_base_body, resp, choose_step_auditor)
            else:
                assert False, f'code不存在，返回【{resp.text}】'
        # 协商请求
        elif approve_params['action'][0].lower() == '协商':
            resp = self.consult(approve_params, approve_base_body)
        # 回复协商请求
        elif approve_params['action'][0].lower() == '回复协商':
            resp = self.reply_consult(approve_params, approve_base_body)
        # 交办
        elif approve_params['action'][0].lower() == '交办':
            resp = self.assigned(approve_params, approve_base_body)
        # 作废
        elif approve_params['action'][0].lower() == '作废':
            resp = self.cancel(approve_params, approve_base_body)
        # 终止
        elif approve_params['action'][0].lower() == '终止':
            resp = self.terminate(approve_params, approve_base_body)
        # 加签
        elif approve_params['action'][0].lower() == '加签':
            resp = self.addSign(approve_params, approve_base_body)
        # 催办
        elif approve_params['action'][0].lower() == '催办':
            resp = self.reminder_by_open_details(approve_params)
        # 传阅
        elif approve_params['action'][0].lower() == '传阅':
            resp = self.circulate_by_open_details(approve_params)
        else:
            print(f'【{approve_params["action"][0]}】操作不存在，请确认！！！')
            assert False, f'【{approve_params["action"][0]}】操作不存在，请确认！！！'
        return resp

    def _confirm_step_path_and_submit(self, url, approve_base_body, resp, choose_step_auditor=None):
        """
        如果是发起明确路径和责任为否，需要二次确认路径或者选择路径分支并提交
        :param url: 审批提交的url
        :param approve_base_body: 审批提交的body
        :param resp: 第一次审批提交的响应，或者是选择分支请求的响应
        :choose_step_auditor: 需要选择的步骤责任人,# choose_step_auditor = [{step_name: '单人审批允许跳过，抄送发起人', auditor: ['李乾芳']},...]
        :return: 返回第二次确认路径后的提交参数
        """
        actual_steps = jsonpath(resp.json(), '$.data.actual_steps')
        # 选择分支后的请求响应有actual_steps，如果无需选择分支，第一次审批提交的响应，则只有actuals
        if actual_steps:    # actual_steps的jsonpath为False，说明未传入选择分支的响应，无需选择分支
            actuals = actual_steps[0]
        else:   # 否则传入的是第一次审批提交的响应
            # 获取确认路径返回的所有路径actuals
            actuals = jsonpath(resp.json(), '$.data.actuals')[0]
            actuals.pop(0)  # 需要删除掉本步骤的步骤信息，index是0
        actual_steps = self.update_steps_by_auditor(actuals, choose_step_auditor)
        approve_base_body.update(actuals=actual_steps)
        resp = self.send(url, method='post', payload=approve_base_body)
        return resp

    def can_reject_steps(self, node_id,csrf_token=''):
        """
        打回时，获取可打回的步骤
        :param node_id:
        :return: 返回可打回的选项信息
        """
        url = '/flowinstance/approval/can-reject-steps'
        if csrf_token=='':
            csrf_token = self.csrf_token
        json_body = {"node_id": node_id}
        resp = self.send(url, method='post', payload=json_body, X_CSRF_Token=csrf_token)
        return resp

    def approval_withdraw(self,open_instance_response, process_name,withdraw_reason):
        """
        审批撤回
        :param open_instance_response: 打开流程的响应
        :param process_name: 流程名称
        :param withdraw_reason: 撤回原因
        :return:
        """
        # 通过打开流程返回的html，获取token，params，tpldata
        instance_response = self.get_key_by_process_instance(open_instance_response)
        token = instance_response['token']
        params = instance_response['params']
        tpldata = instance_response['tpldata']
        params.pop('data_control')
        # 撤回请求的form_data参数获取和组装
        form_data = {}
        children = self.jsonpath_value(tpldata, '$.form.form_data.children')
        fieldSources = self.jsonpath_value(tpldata, '$.form.form_data.fieldSources')
        main = self.jsonpath_value(tpldata, '$.form.form_data.main')
        attachmentTypes = self.jsonpath_value(tpldata, '$.form.form_data.attachmentTypes')
        form_data.update(children=children, fieldSources=fieldSources, main=main, attachmentTypes=attachmentTypes)
        # 组装完整的撤回请求body
        body = {}
        body.update(params,form_data=form_data,opinion=withdraw_reason,manual_execution=False)
        url = f'/flowinstance/approval/withdraw?prc_name={process_name}'
        resp = self.send(method='post', url=url, payload=body, X_CSRF_Token=token)
        return resp

    def approval_rights(self, right=None, **kwargs):
        """
        组装能自动进行完整审批的入参
        :param right:
        :param kwargs: auditors列表，填入实际名称
        :return:
        """
        if right is None:
            return ['同意', {'handText': '自动审批同意'}]
        elif right.lower() == 'vote':
            return ['表决', {'handText': '表决意见', 'vote': '同意'}]
        elif right.lower() == 'terminate':
            return ['终止', {'handText': '自动审批终止'}]
        elif right.lower() == 'rollback':
            return ['驳回', {'handText': '自动打回发起', 'RollBackTo': '发起', 'RollBackType': '重走'}]
        elif right.lower() == 'consult':
            return ['协商', {'handText': '自动发起协商', 'ConsultTo': [kwargs['auditors'][0]]}]
        elif right.lower() == 'circulate':
            return '传阅'
        elif right.lower() == 'cancel':
            return ['作废', {'handText': '自动作废流程测试'}]
        elif right.lower() == 'assigned':
            return ['交办', {'handText': '自动发起交办', 'AssignedTo': kwargs['auditors'][0]}]
        elif right.lower() == 'addsign':
            return ['加签', {'handText': '自动加签测试', 'AddSignAfter': '下一步', 'AddSignTo': kwargs['auditors']}]
        elif right.lower() == 'book':
            return ['归档', {'handText': '自动测试归档'}]
        else:
            return ['同意', {'handText': '自动审批同意'}]

class Approve_Action(Common_Api):
#     def __init__(self,process_name):
#         super().__init__()
#         self.process_name = process_name
    def approve(self):
        pass
    def vote(self):
        pass
    def book(self):
        pass
    def terminate(self):
        pass
    def cancel(self):
        pass
    def reject(self,approve_params, approve_base_body, user_orgs_resp=None):
        pass
    def addSign(self):
        pass
    def assigned(self):
        pass
    def consult(self):
        pass
    def circulate(self):
        pass
